//
//  SFMovableGroupAndItemTableViewController.m
//  DMP
//
//  Created by 支晓辉 on 16/4/8.
//  Copyright © 2016年 Lxit. All rights reserved.
//

#import "SFMovableGroupAndItemTableViewController.h"

#import "SFGroupItem.h"

typedef NSMutableDictionary<NSString*, NSMutableArray<SFMovableView*>*> SFMovableCache;

#define INDEX_PATH(section, row) [NSIndexPath indexPathForRow:row inSection:section]

@interface SFMovableGroupAndItemTableViewController ()
/** 当前移动的视图的截图 */
@property (strong, nonatomic) UIImageView *currentMovableView;
/** 当前视图与原点的偏移 */
@property (assign, nonatomic) CGPoint currentMovableViewOffset;
/** 将要移动到的目标cell */
@property (weak, nonatomic) SFMovableGroupAndItemTableViewCell *willMoveToCell;
/** 当前正在移动的子项所在的cell */
@property (weak, nonatomic) SFMovableGroupAndItemTableViewCell *currentMovingItemCell;
/** 将要移动到的索引 */
@property (assign, nonatomic) NSInteger willMoveToIndex;
/** 从哪个组开始 */
@property (weak, nonatomic) SFGroup *fromGroup;
/** 移动开始的位置的索引 */
@property (assign, nonatomic) NSInteger fromIndex;
/** 当前正在移动的item */
@property (weak, nonatomic) SFGroupItem *currentMoveItem;
/** 当前正在移动的子视图的标签 */
@property (strong, nonatomic) id movableViewTag;
/** 当前正在发生长按手势的识别器 */
@property (weak, nonatomic) UILongPressGestureRecognizer *currentMovableViewLongPressGesture;
/** 开始移动的时候的组 */
@property (weak, nonatomic) SFGroup *startGroup;
/** 结束移动的时候视图 */
@property (weak, nonatomic) UIView *endView;

/** 重用资源 */
@property (strong, nonatomic) NSMutableDictionary<NSString*, id> *reuseSources;
/** 缓存视图 */
@property (strong, nonatomic) SFMovableCache *cacheViews;

@end

@implementation SFMovableGroupAndItemTableViewController

#pragma mark - init

- (instancetype)init {
    if (self = [super init]) {
        [self initValues];
    }
    return self;
}

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        [self initValues];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [self initValues];
    }
    return self;
}

#pragma mark - Life cycle

- (void)viewDidLoad {
    [super viewDidLoad];
    [self initTableView_SFMovableGroupAndItemViewController];
}

#pragma mark - Public methods

- (BOOL)canMoveItemFromIndexPath:(NSIndexPath *)srcIndexPath toIndexPath:(NSIndexPath *)destIndexPath {
    return YES;
}

- (void)didEndMoveChildItemFromCell:(SFMovableGroupAndItemTableViewCell*)fromCell toCell:(SFMovableGroupAndItemTableViewCell*)toCell {
    
}

#pragma mark - Override

- (void)moveRowFromIndexPath:(NSIndexPath *)srcIndexPath toIndexPath:(NSIndexPath *)destIndexPath {
    NSInteger srcIndex = srcIndexPath.row,
    destIndex = destIndexPath.row;
    id targetObj = self.tableData[srcIndex];
    [self.tableData removeObject:targetObj];
    if (destIndex >= self.tableData.count) {
        [self.tableData addObject:targetObj];
    } else {
        [self.tableData insertObject:targetObj atIndex:destIndex];
    }
}

-  (BOOL)canMoveIndexPathFrom:(NSIndexPath *)srcPath toIndexPath:(NSIndexPath *)destPath {
    return YES;
}

- (void)movableTableViewDidAutoScroll {
    [self movableView:self.movableViewTag dealWithLongPressGesture:self.currentMovableViewLongPressGesture];
}

#pragma mark - Private methods

/**
 *  初始化一些值
 */
- (void)initValues {
    self.willMoveToIndex = -1;
}

/**
 *  初始化列表视图
 */
- (void)initTableView_SFMovableGroupAndItemViewController {
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(dealWithLongPressGesture:)];
    gesture.numberOfTouchesRequired = 1;
    gesture.minimumPressDuration = 0.5f;
    [self.tableView addGestureRecognizer:gesture];
}

/**
 *  处理TableView的长按事件
 *
 *  @param gesture 长按手势的识别器
 */
- (void)dealWithLongPressGesture:(UILongPressGestureRecognizer*)gesture {
    CGPoint globalLoc = [gesture locationInView:[UIApplication sharedApplication].keyWindow];
    if (gesture.state == UIGestureRecognizerStateBegan) {
        for (SFMovableGroupAndItemTableViewCell *c in self.tableView.visibleCells) {
            CGRect globalCellRect = [self.tableView convertRect:c.frame toView:[UIApplication sharedApplication].keyWindow];
            if (CGRectContainsPoint(globalCellRect, globalLoc)) {
                SFMovableView *movableView = [c getMovableViewByPoint:globalLoc];
                if (movableView) {
                    [self movableView:movableView dealWithLongPressGesture:gesture];
                    self.currentMovingItemCell = c;
                } else {
                    [gesture cancelsTouchesInView];
                }
            }
        }
    } else if (self.movableViewTag) {
        [self movableView:self.movableViewTag dealWithLongPressGesture:gesture];
    }
}

/**
 *  cell内的组移动的时候调用的方法
 *
 *  @param gesture     移动事件的手势实例
 */
- (void)movableViewMoveWithGesture:(UILongPressGestureRecognizer*)gesture {
    /** 是否有匹配的cell */
    BOOL isIntersectCell = NO;
    for (SFMovableGroupAndItemTableViewCell *c in self.tableView.visibleCells) {
        if (!c.groupData.expanded) {    //没有展开的项忽略掉
            continue;
        }
        CGRect screenRect = [self.tableView convertRect:c.frame toView:[UIApplication sharedApplication].keyWindow];
        if (CGRectIntersectsRect(screenRect, self.currentMovableView.frame)) {
            NSInteger intersectIndex = [c intersectMovableViewRectWith:self.currentMovableView.frame
                                                            filterItem:self.fromGroup.childData[self.fromIndex]];
            //intersectIndex有可能等于-1(当进入的cell中没有任何数据的时候)
            if (intersectIndex != NSNotFound && intersectIndex >= 0) {
                self.willMoveToCell = c;
                self.willMoveToIndex = intersectIndex;
                isIntersectCell = YES;
                break;
            } else if (c.groupData.childData.count <= 0) {  //没有数据的行
                self.willMoveToCell = c;
                self.willMoveToIndex = 0;
                isIntersectCell = YES;
                break;
            }
        }
    }
    if (!isIntersectCell) {
        self.willMoveToCell = nil;
        self.willMoveToIndex = -1;
    }
    //处理自动滑动
    CGPoint location      = [gesture locationInView:[UIApplication sharedApplication].keyWindow];
    CGRect tableViewFrame = self.tableView.frame;
    if (CGRectIntersectsRect(tableViewFrame, self.currentMovableView.frame)) {    //首先滑动的视图必须与当前tableView相交
        if (location.y >= CGRectGetMinY(tableViewFrame) &&
            location.y <= CGRectGetMinY(tableViewFrame) + 44.f) {           //向上移动
            [self tryToAutoScroll:NO];
        } else if (location.y <= CGRectGetMaxY(tableViewFrame) &&
                   location.y >= CGRectGetMaxY(tableViewFrame) - 44.f) {    //向下移动
            [self tryToAutoScroll:YES];
        } else {
            [self stopAutoScrollTimerIfNeed];
        }
    }
}

/**
 *  结束移动的处理操作
 *
 *  @param view 发生移动事件的目的视图
 */
- (void)endMovableViewMovaWithItem:(SFGroupItem*)item {
    SFMovableGroupAndItemTableViewCell *fromCell = nil;
    BOOL canMove = YES;                                 //!< 是否可以移动
    NSInteger fromSection = [self.tableData indexOfObject:self.fromGroup];                  //!< 来源组索引
    NSInteger toSection = [self.tableData indexOfObject:self.willMoveToCell.groupData];   //!< 目标组索引
    //移动开始的cell还是否在可视范围内
    for (SFMovableGroupAndItemTableViewCell *cell in self.tableView.visibleCells) {
        if (cell.groupData == self.fromGroup) {
            fromCell = cell;
            break;
        }
    }
    [self.tableView beginUpdates];
    
    NSInteger destIndex = self.willMoveToIndex;
    SFMovableGroupAndItemTableViewCell *destCell = self.willMoveToCell;
    
    if (fromCell) {     //如果来源的cell在可视范围内
        if (self.willMoveToCell == fromCell) {
            
            //通过调用该方法获知是否允许移动到目的位置
            canMove = [self canMoveItemFromIndexPath:INDEX_PATH(fromSection, self.fromIndex)
                                         toIndexPath:INDEX_PATH(toSection, self.willMoveToIndex)];
            if (canMove) {
                [fromCell moveDataFrom:self.fromIndex
                                    to:self.willMoveToIndex
                              animated:YES
                              complete:^{
                                  SFMovableView *toMovableView = [destCell movableViewAtIndex:destIndex];
                                  self.endView = toMovableView;
                              }];
                [self.willMoveToCell movableViewAtIndex:self.willMoveToIndex].isMoving = YES;
                //回调结束移动
                [self didEndMoveChildItemFromCell:fromCell toCell:self.willMoveToCell];
                
                self.currentMovingItemCell = self.willMoveToCell;
                self.fromIndex = self.willMoveToIndex;
            } else {
                SFMovableView *fromMovableView = [fromCell movableViewAtIndex:self.fromIndex];
                self.endView = fromMovableView;
            }
        } else {    //如果不能够移动
            if (self.willMoveToCell.groupData.childData.count - 1 == self.willMoveToIndex) {
                //跨组移动从结尾进入
                self.willMoveToIndex = self.willMoveToCell.groupData.childData.count;
                destIndex            = self.willMoveToIndex;
            }
            
            //通过调用该方法获知是否允许移动到目的位置
            canMove = [self canMoveItemFromIndexPath:INDEX_PATH(fromSection, self.fromIndex)
                                         toIndexPath:INDEX_PATH(toSection, self.willMoveToIndex)];
            if (canMove) {
                [fromCell deleteDataAt:self.fromIndex animated:YES];
                [self.willMoveToCell insertDataAt:self.willMoveToIndex
                                             data:item
                                         animated:YES
                                         complete:^{
                                             SFMovableView *toMovableView = [destCell movableViewAtIndex:destIndex];
                                             self.endView = toMovableView;
                                         }];
                [self.willMoveToCell movableViewAtIndex:self.willMoveToIndex].isMoving = YES;
                //回调结束移动
                [self didEndMoveChildItemFromCell:fromCell toCell:self.willMoveToCell];
                
                self.currentMovingItemCell = self.willMoveToCell;
                //变换成当前位置，以方便以后的移动
                self.fromGroup = self.willMoveToCell.groupData;
                self.fromIndex = self.willMoveToIndex;
            } else {
                SFMovableView *fromMovableView = [fromCell movableViewAtIndex:self.fromIndex];
                self.endView = fromMovableView;
            }
        }
        
        self.willMoveToIndex = -1;
        self.willMoveToCell  = nil;
    } else {            //如果来源cell不在可视范围内
        //因为来源组不在视图范围内，所以直接在数据列表中把数据移除掉就可以了
        [self.fromGroup.childData removeObject:item];
        if (self.willMoveToCell.groupData.childData.count - 1 == self.willMoveToIndex) {
            //跨组移动从结尾进入
            self.willMoveToIndex = self.willMoveToCell.groupData.childData.count;
            destIndex            = self.willMoveToIndex;
        }
        
        //通过调用该方法获知是否允许移动到目的位置
        canMove = [self canMoveItemFromIndexPath:INDEX_PATH(fromSection, self.fromIndex)
                                     toIndexPath:INDEX_PATH(toSection, self.willMoveToIndex)];
        
        if (canMove) {
            //动画插入数据
            [self.willMoveToCell insertDataAt:self.willMoveToIndex
                                         data:item
                                     animated:YES
                                     complete:^{
                                         SFMovableView *toMovableView = [destCell movableViewAtIndex:destIndex];
                                         self.endView = toMovableView;
                                     }];
            [self.willMoveToCell movableViewAtIndex:self.willMoveToIndex].isMoving = YES;
            //回调结束移动
            [self didEndMoveChildItemFromCell:fromCell toCell:self.willMoveToCell];
            
            self.currentMovingItemCell = self.willMoveToCell;
            //变换成当前位置，以方便以后的移动
            self.fromGroup       = self.willMoveToCell.groupData;
            self.fromIndex       = self.willMoveToIndex;
        } else {
            SFMovableView *fromMovableView = [fromCell movableViewAtIndex:self.fromIndex];
            self.endView = fromMovableView;
        }
        self.willMoveToIndex = -1;
        self.willMoveToCell  = nil;
    }
    [self.tableView endUpdates];
}

#pragma mark - SFMovableItemViewDequeueDelegate

- (SFMovableView *)dequeueWithMovableViewIdentifier:(NSString *)identifier {
    if (!identifier) {
        return nil;
    } else if (!self.reuseSources[identifier]) {
        return nil;
    }
    
    NSMutableArray<__kindof SFMovableView*> *caches = self.cacheViews[identifier];
    if (![caches isKindOfClass:[NSMutableArray class]]) {
        caches = [NSMutableArray array];
        self.cacheViews[identifier] = caches;
    }
    
    if (caches.count > 0) {
        SFMovableView *v = caches.firstObject;
        if (!v.superview && !v.isMoving) {
            [caches removeObject:v];
            [caches addObject:v];
            return v;
        }
    }
    
    id src = self.reuseSources[identifier];
    
    if ([src isKindOfClass:[UINib class]]) {
        SFMovableView *v = [((UINib*)src) instantiateWithOwner:nil options:nil].firstObject;
        if ([v isKindOfClass:[SFMovableView class]]) {
            [v setValue:identifier forKey:@"reuseIdentifier"];
            [caches addObject:v];
            return v;
        }
    } else if ([src respondsToSelector:@selector(isSubclassOfClass:)]) {
        Class cls = (Class)src;
        if ([cls isSubclassOfClass:[SFMovableView class]]) {
            MOVABLE_VIEW *v = [[cls alloc] init];
            [v setValue:identifier forKey:@"reuseIdentifier"];
            [caches addObject:v];
            return v;
        }
    }
    
    return nil;
}

- (void)unuseWithMovableView:(SFMovableView *)movableView {
    NSString *reuseIdentifier = movableView.reuseIdentifier;
    if (reuseIdentifier) {
        NSMutableArray<SFMovableView*> *caches = self.cacheViews[reuseIdentifier];
        if (![caches isKindOfClass:[NSMutableArray class]]) {
            return;
        }
        movableView.isMoving = NO;
        movableView.parent   = nil;
        movableView.item     = nil;
        [caches removeObject:movableView];
        [caches insertObject:movableView atIndex:0];
    }
}

- (void)registNib:(UINib *)nib movableViewIdentifier:(NSString *)identifier {
    if (!identifier) {
        MKLog(@"Cell reuse identifier can not be nil");
        return;
    }
    self.reuseSources[identifier] = nib;
}

- (void)registClass:(Class)viewClass movableViewIdentifier:(NSString *)identifier {
    if (![viewClass isSubclassOfClass:[SFMovableView class]]) {
        MKLog(@"Regiser class failed! Because the class is not a SFMovableView's sub class.");
        return;
    }
    if (!identifier) {
        MKLog(@"Cell reuse identifier can not be nil");
        return;
    }
    self.reuseSources[identifier] = viewClass;
}

#pragma mark - UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.tableData.count;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [SFMovableGroupAndItemTableViewCell calcRowHeightWithGroup:self.tableData[indexPath.row]];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    SFMovableGroupAndItemTableViewCell *cell = (SFMovableGroupAndItemTableViewCell*)[super tableView:tableView cellForRowAtIndexPath:indexPath];
    if (!cell.dequeueDelegate) {
        cell.dequeueDelegate = self;
    }
    if (indexPath.row < self.tableData.count) {
        SFGroup *group                  = self.tableData[indexPath.row];
        if (cell.groupData != group) {
            cell.groupData = group;
        }
    }
    
    return cell;
}

#pragma mark - UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
}

#pragma mark - SFMovableViewDelegate

- (void)movableView:(SFMovableView *)view dealWithLongPressGesture:(UILongPressGestureRecognizer *)gesture {
    switch (gesture.state) {
        case UIGestureRecognizerStateBegan:
        {
            if (self.movableViewTag) {
                return;
            }
            self.endView = view;
            self.currentMovableViewLongPressGesture = gesture;
            self.movableViewTag                     = view;
            self.startGroup                         = view.parent;
            CGRect targetRect                       = view.frame;
            targetRect.origin                       = CGPointZero;
            UIGraphicsBeginImageContext(targetRect.size);
            [view drawViewHierarchyInRect:targetRect afterScreenUpdates:YES];
            UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            //下面这句的位置必须在会在截图后才设置成YES，考虑到以后可能会做移动中的时候，被移动项设置成不显示
            view.isMoving                           = YES;
            
            if (!self.currentMovableView) {
                self.currentMovableView = [[UIImageView alloc] init];
            } else if (self.currentMovableView.superview) {
                [self.currentMovableView removeFromSuperview];
            }
            
            CGPoint screenLoc = [gesture locationInView:[UIApplication sharedApplication].keyWindow];
            self.currentMovableViewOffset = [gesture locationInView:view];
            
            self.currentMovableView.frame = CGRectMake(
                                                       screenLoc.x - self.currentMovableViewOffset.x,
                                                       screenLoc.y - self.currentMovableViewOffset.y,
                                                       CGRectGetWidth(targetRect),
                                                       CGRectGetHeight(targetRect)
                                                       );
            self.currentMovableView.image              = snapshot;
            self.currentMovableView.alpha              = 0.6f;
            self.currentMovableView.contentScaleFactor = [UIScreen mainScreen].scale;
            
            self.currentMovableView.layer.shadowColor   = [UIColor blackColor].CGColor;
            self.currentMovableView.layer.shadowOffset  = CGSizeMake(5.f, 5.f);
            self.currentMovableView.layer.shadowRadius  = 5.f;
            self.currentMovableView.layer.shadowOpacity = 0.6f;

            self.fromGroup                             = view.parent;
            self.fromIndex                             = [view.parent.childData indexOfObject:view.item];
            self.currentMoveItem                       = view.item;
            [[UIApplication sharedApplication].keyWindow addSubview:self.currentMovableView];
            break;
        }
        case UIGestureRecognizerStateCancelled:
        {
            //这里我实在想不到有什么更好的方法来实现
            NSInteger iterateCount = 0;
            for (SFMovableGroupAndItemTableViewCell *c in self.tableView.visibleCells) {
                if (c.groupData == self.startGroup) {
                    break;
                }
                iterateCount++;
            }
            if (iterateCount == self.tableView.visibleCells.count) {    //视图是因为被移除才引发的
                //这个时候的cancel事件是因为autoScroll所引发的，因此忽略
                break;
            }
        }
        case UIGestureRecognizerStateFailed:
        case UIGestureRecognizerStateEnded:         //结束长按拖动事件
        {
            self.tableView.scrollEnabled = NO;
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [UIView animateWithDuration:0.3f animations:^{
                    if (self.endView) {     //如果结束为止的视图不为空则使用结束移动位置的视图
                        self.currentMovableView.frame = [self.endView.superview convertRect:self.endView.frame toView:[UIApplication sharedApplication].keyWindow];
                    } else {                //否则视图已经被释放，可能已经不存在
                        SFMovableGroupAndItemTableViewCell *intersectCell = (id)[self intersetCellWithRect:self.currentMovableView.frame];
                        NSInteger currentIntersetCellIndex = [self.tableData indexOfObject:intersectCell.groupData];
                        NSInteger fromGroupIndex = [self.tableData indexOfObject:self.fromGroup];
                        if (currentIntersetCellIndex > fromGroupIndex) {    //组在上面
                            self.currentMovableView.frame = CGRectMake(
                                                                       0,
                                                                       -CGRectGetHeight(self.currentMovableView.frame),
                                                                       CGRectGetWidth(self.currentMovableView.frame),
                                                                       CGRectGetHeight(self.currentMovableView.frame)
                                                                       );
                        } else {                                            //组在下面
                            self.currentMovableView.frame = CGRectMake(
                                                                       0,
                                                                       CGRectGetMaxY([UIApplication sharedApplication].keyWindow.frame),
                                                                       CGRectGetWidth(self.currentMovableView.frame),
                                                                       CGRectGetHeight(self.currentMovableView.frame)
                                                                       );
                        }
                    }
                } completion:^(BOOL finished) {
                    [self.currentMovableView removeFromSuperview];
                    self.endView = nil;
                    self.tableView.scrollEnabled = YES;
                    [self.currentMovingItemCell movableViewAtIndex:self.fromIndex].isMoving = NO;
                    self.currentMovingItemCell = nil;
                }];
            });
            
            [self stopAutoScrollTimerIfNeed];
            self.movableViewTag                     = nil;
            self.startGroup                         = nil;
            self.currentMovableViewLongPressGesture = nil;
            break;
        }
        case UIGestureRecognizerStateChanged:       //长按拖动中的时候
        {
            if (self.currentMovableView) {
                self.currentMovableViewLongPressGesture = gesture;
                CGPoint pos = [gesture locationInView:[UIApplication sharedApplication].keyWindow];
                pos.x -= self.currentMovableViewOffset.x;
                pos.y -= self.currentMovableViewOffset.y;
                CGRect movableViewRect = self.currentMovableView.frame;
                movableViewRect.origin = pos;
                self.currentMovableView.frame = movableViewRect;
            }
            [self movableViewMoveWithGesture:gesture];
            if (self.willMoveToIndex == -1 ||
                !self.willMoveToCell) {     //没有匹配的移动视图
                return;
            }
            
            [self endMovableViewMovaWithItem:self.currentMoveItem];
            break;
        }
            
        default:
            break;
    }
}

#pragma mark - Getters

- (NSMutableDictionary<NSString *,id> *)reuseSources {
    if (!_reuseSources) {
        _reuseSources = [NSMutableDictionary dictionary];
    }
    return _reuseSources;
}

- (SFMovableCache*)cacheViews {
    if (!_cacheViews) {
        _cacheViews = [NSMutableDictionary dictionary];
    }
    return _cacheViews;
}

- (NSMutableArray<SFGroup *> *)tableData {
    
    if (!_tableData) {
        _tableData = [NSMutableArray array];
    }
    
    return _tableData;;
}

@end
